/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package studio.raptor.ddal.core.engine;

import java.io.Closeable;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import studio.raptor.ddal.config.config.ShardConfig;
import studio.raptor.ddal.config.model.shard.VirtualDb;
import studio.raptor.ddal.core.connection.ContextConnectionWrapper;
import studio.raptor.ddal.core.constants.DatabaseType;
//import studio.raptor.ddal.core.transaction.DefaultTransactionIdGenerator;
//import studio.raptor.ddal.core.transaction.TransactionIdGenerator;
//import studio.raptor.ddal.core.transaction.TransactionLogRecorder;

/**
 * Execute context for raptor ddal core. This context is designed to hold several
 * runtime objects listed below.
 * <ul>
 * <li>Physical database connection mapped to each virtual shard.</li>
 * <li>Original sql scripts received from app client.</li>
 * <li>Shard result of origin sql which is produced by RouteEngine.</li>
 * </ul>
 *
 * @author Sam
 * @since 1.0
 */
public class ProcessContext implements Closeable {

  /**
   * 虚拟数据库
   */
  private VirtualDb virtualDb;

  private StatementContext statementContext;

  private boolean autoCommit; // jdbc事务是否自动提交
  private DatabaseType databaseType;

  private StatementContext statementContextForIdx=null;//批处理操作时索引副本模式下的执行上下文

  private String transactionId = null; //事务ID
  // fixme 不要删除
//  private TransactionIdGenerator txIdGenerator = new DefaultTransactionIdGenerator();
//  private TransactionLogRecorder txLogRecorder = new TransactionLogRecorder();

  /**
   * 执行过程中使用的所有后端物理连接。{shardName:BackendConnection}
   *
   * Concurrency issue fixed
   * 多个SQL执行单元共享此变量，所以存在多个执行单元并发执行时出现
   * 后端连接丢失从而造成连接池无法正常回收连接的问题。
   */
  private Map<String, ContextConnectionWrapper> shardBackendConnectionsWrapper = new ConcurrentHashMap<>();

  /**
   * a constant indicating whether auto-generated keys should be made available
   * for retrieval using the method <code>getGeneratedKeys</code>; one of the
   * following constants: <code>Statement.RETURN_GENERATED_KEYS</code> or
   * <code>Statement.NO_GENERATED_KEYS</code>
   */
  private boolean retrieveGeneratedKeys = false;

  public ProcessContext(DatabaseType databaseType, String virtualDbName) {
    this.databaseType = databaseType;
    this.virtualDb = ShardConfig.getInstance().getVirtualDb(virtualDbName);
  }

  public VirtualDb getVirtualDb() {
    return virtualDb;
  }


  public StatementContext getStatementContext() {
    return statementContext;
  }

  public void setStatementContext(StatementContext statementContext) {
    this.statementContext = statementContext;
  }


  /**
   * 设置当前执行上下文的事务提交方式。
   *
   * FALSE：表示当前上下文可执行多条语句直至连接使用者触发commit操作才会提交事务。
   * TRUE：每条sql都在单独的事务中执行。
   *
   * @param autoCommit true or false
   */
  public void setAutoCommit(boolean autoCommit) {
    this.autoCommit = autoCommit;
  }

  public boolean isAutoCommit() {
    return autoCommit;
  }

  public DatabaseType getDatabaseType() {
    return databaseType;
  }


  public Map<String, ContextConnectionWrapper> getShardBackendConnWrapper() {
    return shardBackendConnectionsWrapper;
  }

//  public boolean hasReadonlyHint() {
//    return hasReadonlyHint;
//  }
//
//  public void setHasReadonlyHint(boolean hasReadonlyHint) {
//    this.hasReadonlyHint = hasReadonlyHint;
//  }


  public boolean isRetrieveGeneratedKeys() {
    return retrieveGeneratedKeys;
  }

  public void setRetrieveGeneratedKeys(boolean retrieveGeneratedKeys) {
    this.retrieveGeneratedKeys = retrieveGeneratedKeys;
  }

// fixme 不要删除
//  public TransactionLogRecorder getTxLogRecorder() {
//    return txLogRecorder;
//  }

  public String getTransactionId() {
    return transactionId;
  }

  public void setTransactionId(String transactionId) {
    this.transactionId = transactionId;
  }
// fixme 不要删除
//  public TransactionIdGenerator getTxIdGenerator() {
//    return txIdGenerator;
//  }


  @Override
  public void close() throws IOException {
    if(null != statementContext){
      statementContext.close();
    }
  }

  public void clear() {
    try{
      if(null != statementContext) {
        statementContext.close();
      }
    }catch(Exception ignore){}
  }

  public StatementContext getStatementContextForIdx() {
    return statementContextForIdx;
  }

  public void setStatementContextForIdx(StatementContext statementContextForIdx) {
    this.statementContextForIdx = statementContextForIdx;
  }
}
